package za.co.chris.traintimes.database;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Scanner;

import za.co.chris.traintimes.beans.Line;
import za.co.chris.traintimes.beans.Station;
import za.co.chris.traintimes.beans.TimeBean;
import za.co.chris.traintimes.beans.TimeElement;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.util.SparseArray;

public class DatabaseHelper {

	private SQLiteDatabase database;
	private final TrainTimesDatabase dbHelper;
	private final List<Line> lineNames = new ArrayList<Line>();
	private final SparseArray<Station> stationsById = new SparseArray<Station>();
	private final HashMap<String, Station> stationsByName = new HashMap<String, Station>();
	private final HashMap<String, List<Station>> allStations = new HashMap<String, List<Station>>();
	private final Context context;
	private static DatabaseHelper helper;

	public static DatabaseHelper getInstance(Context context) {
		if (helper == null) {
			helper = new DatabaseHelper(context);
		}
		return helper;
	}

	public DatabaseHelper(Context context) {
		dbHelper = new TrainTimesDatabase(context);
		this.context = context;
	}

	public void open() throws SQLException {
		database = dbHelper.getWritableDatabase();
		Cursor cursor = database.query("sqlite_sequence", new String[] { "name" }, null, null, null, null, null);
		if (cursor.getCount() == 0) {
			populate(database);
		}
	}

	public void close() {
		dbHelper.close();
	}

	public List<Line> getLines() {
		Cursor results = database.query("sqlite_sequence", new String[] { "name" }, null, null, null, null, null);
		results.moveToFirst();
		while (!results.isAfterLast()) {
			lineNames.add(new Line(results.getString(results.getColumnIndex("name"))));
			results.moveToNext();
		}
		return lineNames;
	}

	public List<Station> getStationsOnLine(String line) {
		List<Station> resultList = new ArrayList<Station>();
		if (!allStations.containsKey(line)) {
			Cursor results = database.query(line, null, null, null, null, null, null);
			for (String stationName : Arrays.asList(results.getColumnNames())) {
				resultList.add(new Station(stationName, line));
			}
			resultList = resultList.subList(4, resultList.size());
			allStations.put(line, resultList);
		} else {
			resultList = allStations.get(line);
		}
		return resultList;
	}

	private void populate(SQLiteDatabase database) {
		InputStream lineInputStream = null;
		HashMap<String, Line> lines = new HashMap<String, Line>();
		HashMap<String, Station> stations = new HashMap<String, Station>();
		try {
			String[] lineFiles = context.getAssets().list("lines");
			Scanner in;
			for (String lineFile : lineFiles) {
				lineInputStream = context.getAssets().open("lines/" + lineFile);
				String[] columnHeaders;
				if (lineInputStream != null) {
					in = new Scanner(lineInputStream);
					columnHeaders = in.nextLine().split(",", -1);
					while (in.hasNext()) {
						String[] entries = in.nextLine().split(",", -1);
						ContentValues values = new ContentValues();
						for (int i = 0; i < columnHeaders.length; i++) {
							values.put(columnHeaders[i].replace(" ", "_"), entries[i]);
						}
						long index = database.insert(lineFile.substring(5, lineFile.length() - 4), null, values);
					}
				}
			}
		} catch (IOException e) {

		}
	}

	public TimeBean getAndWrapStations(String fromStation, String toStation, String line, String direction, String selectedTime, String day) {
		int selectedtimeInt = parseTimeValue(selectedTime);
		TimeBean timeBean = new TimeBean(line, fromStation, toStation);
		fromStation = fromStation.replace(" ", "_");
		toStation = toStation.replace(" ", "_");
		String clause = " cast(" + fromStation + " as integer) >=" + selectedtimeInt + " and DIRECTION = '" + direction + "' and DAYS like '%" + day + "%' and " + fromStation + " !='' and "
				+ toStation + " !=''";
		Cursor results = database.query(line, new String[] { "Train_No", fromStation, toStation }, clause, null, null, null, null);
		results.moveToFirst();
		while (!results.isAfterLast()) {
			String trainNo = results.getString(results.getColumnIndex(results.getColumnNames()[0]));
			String fromTime = results.getString(results.getColumnIndex(results.getColumnNames()[1]));
			String toTime = results.getString(results.getColumnIndex(results.getColumnNames()[2]));

			timeBean.addTimeElement(new TimeElement(context, trainNo, formatTime(fromTime), formatTime(toTime)));
			results.moveToNext();
		}
		return timeBean;
	}

	public List<Station> getInterchangeList(String fromLine, String toLine) {
		List<Station> fromLineStations = allStations.get(fromLine);
		List<Station> toLineStations = allStations.get(toLine);
		List<Station> interachangeList = new ArrayList<Station>();
		for (Station fromStation : fromLineStations) {
			for (Station toStation : toLineStations) {
				if (fromStation.getStationName().equals(toStation.getStationName())) {
					interachangeList.add(fromStation);
				}
			}
		}
		return interachangeList;
	}

	private int parseTimeValue(String time) {
		if (time.matches("\\d{1,2}:\\d{1,2}")) {
			String hourString = time.split(":")[0];
			String minString = time.split(":")[1];
			int hours = Integer.parseInt(hourString);
			int mins = Integer.parseInt(minString);
			return (hours * 100) + mins;
		}
		return -1;
	}

	private String formatTime(String time) {
		if (time.length() == 3) {
			time = "0" + time;
		}
		return time.substring(0, 2) + ":" + time.substring(2, time.length());
	}

	private <T> String[] getColumnList(Class<T> entity) {
		Field[] fields = entity.getDeclaredFields();
		String[] columns = new String[fields.length];
		for (int i = 0; i < fields.length; i++) {
			columns[i] = fields[i].getName();
		}
		return columns;
	}
}
